package com.wcj.hash;

import java.util.*;

/**
 * 给你一个整数数组 nums 和一个整数 k ，
 * 请你返回其中出现频率前 k 高的元素。你可以按 任意顺序 返回答案。
 *
 * 输入: nums = [1,1,1,2,2,3], k = 2
 * 输出: [1,2]
 */
public class 前K个高频元素 {


    /**
     * 方法一：堆排序
     * @param nums
     * @param k
     * @return
     */
    public int[] topKFrequent(int[] nums, int k) {
        Map<Integer,Integer> occurrences = new HashMap<>();
        for (int num : nums) {
            occurrences.put(num,occurrences.getOrDefault(num,0)+1);
        }
        // int[] 的第一个元素代表数组的值，第二个元素代表了该值出现的次数
        PriorityQueue<int[]> queue = new PriorityQueue<>(new Comparator<int[]>() {
            @Override
            public int compare(int[] o1, int[] o2) {
                return o1[1] - o2[1];
            }
        });
        for (Map.Entry<Integer,Integer> entry : occurrences.entrySet()){
            int num = entry.getKey();
            int count = entry.getValue();
            if (queue.size() == k){
                if (queue.peek()[1] < count){
                    queue.poll();
                    queue.offer(new int[]{num,count});
                }
            }else {
                queue.offer(new int[]{num,count});
            }
        }
        int[] ret = new int[k];
        for (int i = 0; i < k; ++i){
            ret[i] = queue.poll()[0];
        }
        return ret;
    }

    /**
     * 快速排序方法
     * @param nums
     * @param k
     * @return
     */
    public int[] topKFrequent2(int[] nums, int k) {
        Map<Integer,Integer> occurrences = new HashMap<>();
        for (int num : nums) {
            occurrences.put(num,occurrences.getOrDefault(num,0)+1);
        }

        List<int[]> values = new ArrayList<int[]>();
        for (Map.Entry<Integer, Integer> entry : occurrences.entrySet()) {
            int num = entry.getKey();
            int count = entry.getValue();
            values.add(new int[]{num,count});
        }
        int[] ret = new int[k];
        qsort(values,0,values.size() - 1,ret,0,k);
        return ret;
    }

    private void qsort(List<int[]> values, int start, int end, int[] ret, int retIndex, int k) {
        int picked = (int) (Math.random() * (end - start + 1)) + start;
        Collections.swap(values,picked,start);

        int pivot = values.get(start)[1];
        // index指向大于等于pivot列表的最后一个
        int index = start;
        for (int i = start + 1; i <= end; i++){
            if (values.get(i)[1] >= pivot){
                Collections.swap(values,index + 1,i);
                index++;
            }
        }
        Collections.swap(values,start,index);

        if (k <= index - start){
            qsort(values,start,index - 1,ret,retIndex,k);
        }else {
            for (int i = start; i <= index; i++){
                ret[retIndex++] = values.get(i)[0];
            }
            if (k > index - start + 1){
                qsort(values,index + 1,end,ret,retIndex,k-(index - start + 1));
            }
        }
    }


}
